//	COPYRIGHT (C) 1980 BY BOARD OF TRUSTEES,
//	LELAND STANFORD JUNIOR UNIVERSITY

//APRIL 25, 1978
//BCPL-CONGEN, WRITTEN BY RAY CARHART.  THIS FILE CONTAINS THE STRUCTURE
//GENERATOR ITSELF.
LET SGEN(NIN,NUMAT,TVS,TNUMS,TISBS,TADDLISBS,AVOIDISTH) BE
 $(
 STATIC $( VALENCES = NIL; GFA = NIL; TYPNO = NIL; COMPARY = NIL;
           NEXTRAT = 1; NAT = NIL; VL = NIL; VR = NIL; VSUM = NIL;
           COMPPTR = 1; NCLASS = 0; NCLASS1 = 0; CLASSPTR = 1;
           CLASSPTRS = NIL; CLASSES = NIL; VRMAX = NIL;
           REMOVED = NIL; OLDNOS =NIL; NEWNOS = NIL; ADJM = NIL;
           CSCRATCH = NIL; SCORDER = NIL; SCORDINV = NIL; VS = NIL;
           NUMS = NIL; LTPS = NIL; HTPS = NIL; GMTACTICS = NIL;
           ETR = NIL; VLNCSAV = NIL; ISBS = NIL; ADDLISBS = NIL;
           ISBMAXS = NIL; NISB = NIL; AVOIDISTHMUS = NIL $);
 STATIC $( ESTIMATING = NIL; ESTRAT = NIL; ESTARTT = NIL; ESTOPT = NIL;
           ESTARTT0 = NIL $);
 GET "NOISTH.BCL[1,35]"
 GET "ATORD.BCL[1,35]"

 LET CYCTST() = (ANYRINGTESTS -> CYCSOK(1,NAT,CYCMINS,CYCMAXS,DIAMLISTS),TRUE);

 LET TYPN,ATMIN,ATMAX=NIL,NIL,NIL;

 LET STRUCFUN() BE
 $(
 NSTRUCS+:=1;
 OUTPUT:=OUTFILE;
 OUTCH(46);
 OUTNOS(NSTRUCS);
 FOR I=1 TO NAT DO
  $( STATIC $( PTRTOP = NIL; IIMG = NIL; NISB = NIL $);
  IIMG:=SCORDER!I;
  IF ARTYPE!IIMG=2 DO OUTCH([125+48] REM 128);
  NISB:=2*NUMISBS!IIMG;
  WHILE NISB>0 DO $( NISB-:=1; OUTCH([I+48] REM 128) $);
  PTRTOP:=CTSTOP!IIMG;
  FOR J=CTSTART!IIMG TO PTRTOP DO
   OUTCH([SCORDINV![CTABLE!J]+48] REM 128);
  OUTCH(48)
  $);
 OUTCH(47);
 OUTPUT:=TTY;
 OUTCHP('.');
 IF NSTRUCS=STOPAFTER DO $( ESTRPT(FALSE); JUMP(STOPLAB) $);
 ESTRPT(TRUE)
 $);

 LET NBRFN0(ATNO) = VALOF
  $( LET SCORE,PTRTOP,NBR=0,CTSTOP!ATNO,NIL;
  SCORE:=0;
  PTRTOP:=CTSTOP!ATNO;
  FOR CTPTR=CTSTART!ATNO TO PTRTOP DO
   $(
   NBR:=CTABLE!CTPTR;
   IF REMOVED!NBR=0 DO SCORE+:=VALENCES!NBR*VALENCES!NBR+
                                  TYPNO!NBR*TYPNO!NBR+
                                  DOTS!NBR*DOTS!NBR
   $);
   RESULTIS SCORE;
  $);

 LET NBRFN(ATNO) = VALOF
  $( LET SCORE,PTRTOP,NBR=0,CTSTOP!ATNO,NIL;
  SCORE:=0;
  PTRTOP:=CTSTOP!ATNO;
  FOR CTPTR=CTSTART!ATNO TO PTRTOP DO
   $(
   NBR:=CTABLE!CTPTR;
   IF REMOVED!NBR=0 DO SCORE+:=NBRFN0(CTABLE!CTPTR)
   $);
  RESULTIS SCORE;
  $);

 LET CANONFILTER() = VALOF
  $(
  STATIC $( NEWNUM = NIL; FIRSTPERM = NIL; CPTR = NIL; NCL = NIL;
	NNUM = NIL; NSYM = NIL $);

  LET MAKEADJM() BE
   $(
   STATIC $( PTRTOP = NIL; IATOMIX = NIL $);
   IATOMIX:=0;
   FOR IATOM=1 TO NAT DO
    $(
    PTRTOP:=CTSTOP!IATOM;
    FOR PTR=CTSTART!IATOM TO PTRTOP DO ADJM![IATOMIX+CTABLE!PTR]+:=1;
    IATOMIX+:=NAT
    $)
   $);

  LET CLEANADJM() BE
   $(
   STATIC $( PTRTOP = NIL; IATOMIX = NIL $);
   IATOMIX:=0;
   FOR IATOM=1 TO NAT DO
    $(
    PTRTOP:=CTSTOP!IATOM;
    FOR PTR=CTSTART!IATOM TO PTRTOP DO ADJM![IATOMIX+CTABLE!PTR]-:=1;
    IATOMIX+:=NAT
    $)
   $);

  LET BONDHISTTEST(J,K) = VALOF
   $(
   STATIC $( JBO = NIL; KBO = NIL; ONUMIX = NIL $);
   FOR NEWN = NEWNUM+1 TO NAT DO
    $(
    ONUMIX:=[OLDNOS!NEWN-1]*NAT;
    JBO:=ADJM![ONUMIX+J];
    KBO:=ADJM![ONUMIX+K];
    IF JBO NE KBO DO
     TEST JBO>KBO THEN RESULTIS 1 OR RESULTIS -1
    $);
   RESULTIS 0
   $);

  LET UNJOINC(ATOM) BE
   $(
   STATIC $( PTRTOP = NIL; PREVNO = NIL; NBRNO = NIL $);
   NBRNO:=0;
   PTRTOP:=CTSTOP!ATOM;
   FOR PTR=CTSTART!ATOM TO PTRTOP DO
    $(
    PREVNO:=NBRNO;
    NBRNO:=CTABLE!PTR;
    IF REMOVED!NBRNO=0 DO
     $(
     VALENCES!ATOM+:=1;
     VALENCES!NBRNO+:=1;
     IF PREVNO=NBRNO DO
      $(
      DOTS!ATOM-:=1;
      DOTS!NBRNO-:=1
      $)
     $)
    $);
   REMOVED!ATOM:=1
   $);

  LET JOINC(ATOM) BE
   $(
   STATIC $( PTRTOP = NIL; PREVNO = NIL; NBRNO = NIL $);
   NBRNO:=0;
   PTRTOP:=CTSTOP!ATOM;
   FOR PTR=CTSTART!ATOM TO PTRTOP DO
    $(
    PREVNO:=NBRNO;
    NBRNO:=CTABLE!PTR;
    IF REMOVED!NBRNO=0 DO
     $(
     VALENCES!ATOM-:=1;
     VALENCES!NBRNO-:=1;
     IF PREVNO=NBRNO DO
      $(
      DOTS!ATOM+:=1;
      DOTS!NBRNO+:=1
      $)
     $)
    $);
   REMOVED!ATOM:=0
   $);

  LET ADJMORDP(IX,PIX) = VALOF
   $(
   STATIC $( V1 = NIL; V2 = NIL $);
   FOR NBR=1 TO NAT DO
    $(
    IX+:=1;
    V1:=ADJM!IX;
    V2:=ADJM![PIX+OLDNOS!NBR];
    IF V1 NE V2 DO RESULTIS (V1>V2 -> 1,-1)
    $)
   $);

  LET OKPERMP() = VALOF
   $(
   STATIC $( PTRTOP = NIL; NBR = NIL; IAIX = NIL; PIAIX = NIL $);
   IAIX:=0;
   FOR IATOM=1 TO NAT DO
    $(
    PTRTOP:=CTSTOP!IATOM;
    PIAIX:=[OLDNOS!IATOM-1]*NAT;
    FOR PTR=CTSTART!IATOM TO PTRTOP DO
     $(
     NBR:=CTABLE!PTR;
     IF ADJM![IAIX+NBR] NE ADJM![PIAIX+OLDNOS!NBR] DO
      RESULTIS ADJMORDP(IAIX,PIAIX)
     $);
    IAIX+:=NAT
    $);
   RESULTIS 0
   $);

  LET CHOOSEFIRST() = VALOF
   TEST NEWNUM=1 THEN
    TEST FIRSTPERM THEN
     $(
     FIRSTPERM:=FALSE;
     RESULTIS TRUE
     $)
    OR
     $( STATIC $( RES = NIL $);
     NNUM+:=1;
      RES:=OKPERMP();
     IF RES=0 DO NSYM+:=1;
     NEWNOS![OLDNOS!1]:=1;
     RESULTIS RES GE 0
     $)
   OR
    $(
    STATIC $( FANS = NIL $);
    LET OLDNUM = OLDNOS!NEWNUM;
    NEWNOS!OLDNUM:=NEWNUM;
    UNJOINC(OLDNUM);
    NEWNUM-:=1;
    FANS:=CHOOSESET();
    NEWNUM+:=1;
    JOINC(OLDNUM);
    RESULTIS FANS
    $)

  AND CHOOSEONE(INDEX) = VALOF
   $(
   STATIC $( TEM = NIL; OANS = NIL $);
   TEM:=OLDNOS!INDEX;
   OLDNOS!INDEX:=OLDNOS!NEWNUM;
   OLDNOS!NEWNUM:=TEM;
   OANS:=CHOOSEFIRST();
   TEM:=OLDNOS!INDEX;
   OLDNOS!INDEX:=OLDNOS!NEWNUM;
   OLDNOS!NEWNUM:=TEM;
   RESULTIS OANS
   $)

  AND CHOOSESET() = VALOF
   $(
   STATIC $( V = NIL; VMAX = NIL; D = NIL; DMIN = NIL; NF = NIL;
             NFMIN = NIL; CSIZE = NIL; CSIZE2 = NIL; GFANEW = NIL;
             TEMIX = NIL; BHT = NIL; ND1 = NIL; ND2 = NIL $);
   GFANEW:=GFA!NEWNUM;
   IF GFANEW=NEWNUM DO RESULTIS CHOOSEFIRST();
   VMAX:=0;
   DMIN:=1000;
   FOR INDEX=GFANEW TO NEWNUM DO
    $(
    TEMIX:=OLDNOS!INDEX;
    V:=VALENCES!TEMIX;
    D:=DOTS!TEMIX;
    TEST [V>VMAX] BITOR [[V=VMAX] BITAND [D<DMIN]] THEN
     $(
     CSIZE:=1;
     CSCRATCH!1:=INDEX;
     VMAX:=V;
     DMIN:=D
     $)
    OR
     IF [V=VMAX] BITAND [D=DMIN] DO
      $(
      CSIZE+:=1;
      CSCRATCH!CSIZE:=INDEX
      $)
    $);
   IF CSIZE=1 DO RESULTIS CHOOSEONE(CSCRATCH!1);
   NFMIN:=NBRFN(OLDNOS![CSCRATCH!1]);
   CSIZE2:=1;
   FOR INDEX=2 TO CSIZE DO
    $(
    TEMIX:=CSCRATCH!INDEX;
    NF:=NBRFN(OLDNOS!TEMIX);
    TEST NF<NFMIN THEN
     $(
     CSIZE2:=1;
     CSCRATCH!1:=TEMIX;
     NFMIN:=NF
     $)
    OR
     IF NF=NFMIN DO
      $(
      CSIZE2+:=1;
      CSCRATCH!CSIZE2:=TEMIX
      $)
    $);
   IF CSIZE2=1 DO RESULTIS CHOOSEONE(CSCRATCH!1);
   CSIZE:=CSIZE2;
   CSIZE2:=1;
   ND1:=OLDNOS![CSCRATCH!1];
   FOR INDEX=2 TO CSIZE DO
    $(
    TEMIX:=CSCRATCH!INDEX;
    ND2:=OLDNOS!TEMIX;
    BHT:=BONDHISTTEST(ND1,ND2);
    TEST BHT<0 THEN
     $(
     CSIZE2:=1;
     CSCRATCH!1:=TEMIX;
     ND1:=ND2
     $)
    OR
     IF BHT=0 DO
      $(
      CSIZE2+:=1;
      CSCRATCH!CSIZE2:=TEMIX
      $)
    $);
   TEST CSIZE=1 THEN RESULTIS CHOOSEONE(CSCRATCH!1)
   OR
    $(
    LET CSAVE=NEWVEC(CSIZE2-1);
    FOR INDEX=1 TO CSIZE2 DO CSAVE![INDEX-1]:=CSCRATCH!INDEX;
    CSIZE2-:=1;
    FOR INDEX=CSIZE2 TO 0 BY -1 DO
     UNLESS CHOOSEONE(CSAVE!INDEX) DO
      $(
      FREEVEC(CSAVE);
      RESULTIS FALSE
      $);
    FREEVEC(CSAVE);
    RESULTIS TRUE
    $)
   $);
  NEWNUM:=NAT;
  NSYM:=0;
  NNUM:=0;
  MAKEADJM();
  FIRSTPERM:=TRUE;
  UNLESS CHOOSEFIRST() DO
   $(
   CLEANADJM();
   RESULTIS FALSE
   $);
  IF NCLASS1=0 DO $( CLEANADJM(); RESULTIS TRUE $);
  CPTR:=CLASSPTRS!NCLASS1;
  NCL:=CLASSES![CPTR+1];
  IF [NAT NE CLASSES!CPTR] BITOR [NCL=0] DO
   $(
   CLEANADJM();
   RESULTIS TRUE
   $);
  CPTR+:=2;
  FOR CL=1 TO NCL DO
   $(
   CPTR+:=2;
   UNLESS CHOOSEONE(CLASSES!CPTR) DO
    $(
    CLEANADJM();
    RESULTIS FALSE
    $)
   $);
  CLEANADJM();
  RESULTIS TRUE
  $);

 LET HORDATP(NAT) = VALOF
  $( LET V,D,NF,V2,D2,NF2,SIMAT,CPTR,NINCLASS=VALENCES!NAT,DOTS!NAT,
                            NBRFN(NAT),NIL,NIL,NIL,NIL,CLASSPTR+3,0;
  SIMAT:=GFA!NAT-1;
  NAT-:=1;
  $(
   SIMAT+:=1;
   V2:=VALENCES!SIMAT;
   TEST V<V2 THEN RESULTIS FALSE
   OR
    IF V=V2 DO
     $(
     D2:=DOTS!SIMAT;
     TEST D>D2 THEN RESULTIS FALSE
     OR
      IF D=D2 DO
       $(
       NF2:=NBRFN(SIMAT);
       TEST NF>NF2 THEN RESULTIS FALSE
       OR
        IF NF=NF2 DO
         $(
         CLASSES!CPTR:=0;
         CLASSES![CPTR+1]:=SIMAT;
         CPTR+:=2;
         NINCLASS+:=1
         $)
       $)
     $)
  $) REPEATUNTIL SIMAT=NAT;
  IF NINCLASS NE 0 DO
   $(
   CLASSES!CPTR:=-1;
   CPTR+:=1;
   NCLASS+:=1
   $);
  CLASSES!CLASSPTR:=NAT+1;
  CLASSES![CLASSPTR+1]:=NINCLASS;
  CLASSES![CLASSPTR+2]:=0;
  NCLASS1+:=1;
  CLASSPTRS!NCLASS1:=CLASSPTR;
  CLASSPTR:=CPTR;
  RESULTIS TRUE
  $);

 LET UNHORD() BE
  $(
  CLASSPTR:=CLASSPTRS!NCLASS1;
  NCLASS1-:=1;
  IF CLASSES![CLASSPTR+1] NE 0 DO NCLASS-:=1
  $);

 LET TESTCLASSES(NCLASSES) = VALOF
  $( STATIC $( I = NIL; ATOK = NIL; CLPTR = NIL; V = NIL $);
  I:=0;
  WHILE NCLASSES>0 DO
   $(
   I+:=1;
   IF CLASSES![CLASSPTRS!I+1] NE 0 DO
    $(
    NCLASSES-:=1;
    CLPTR:=CLASSPTRS!I;
    V:=VALENCES![CLASSES!CLPTR];
    CLPTR+:=1;
    $(
    CLPTR+:=2;
    ATOK:=CLASSES!CLPTR;
    IF ATOK=0 DO
     IF VALENCES![CLASSES![CLPTR+1]]<V DO RESULTIS FALSE
    $) REPEATUNTIL ATOK=-1
    $)
   $);
  RESULTIS TRUE
 $);

 LET UPDATECLASSES(NCLASSES) = VALOF
  $( STATIC $( I = NIL; ATOK = NIL; CLPTR = NIL; V = NIL; NEWNC = NIL;
               NLOC = NIL; NATCLASS = NIL $);
  NEWNC:=NCLASSES;
  I:=0;
  WHILE NCLASSES>0 DO
   $(
   I+:=1;
   IF CLASSES![CLASSPTRS!I+1] NE 0 DO
    $(
    CLPTR:=CLASSPTRS!I;
    NCLASSES-:=1
    V:=VALENCES![CLASSES!CLPTR];
    CLPTR+:=1;
    NLOC:=CLPTR;
    NATCLASS:=CLASSES!CLPTR;
    $(
    CLPTR+:=2;
    ATOK:=CLASSES!CLPTR;
    IF ATOK=0 DO
     IF VALENCES![CLASSES![CLPTR+1]]>V DO
      $(
      NATCLASS-:=1;
      CLASSES!CLPTR:=NEXTRAT
      $)
    $) REPEATUNTIL ATOK=-1;
    IF NATCLASS NE CLASSES!NLOC DO
     $(
     CLASSES!NLOC:=NATCLASS;
     CLASSES![NLOC+1]:=NEXTRAT;
     IF NATCLASS=0 DO NEWNC-:=1
     $)
    $)
   $);
  RESULTIS NEWNC
  $);

 LET DOWNDATECLASSES(ONCLASSES) BE
  $( STATIC $( I = NIL; CLPTR = NIL; NLOC = NIL; NATCLASS = NIL;
               NEXTHIGHEST = NIL; ATOK = NIL $);
  I:=0;
  WHILE ONCLASSES>0 DO
   $(
   I+:=1;
   CLPTR:=CLASSPTRS!I;
   TEST NEXTRAT=CLASSES![CLPTR+2] THEN
    $(
    ONCLASSES-:=1;
    CLPTR+:=1;
    NLOC:=CLPTR;
    NATCLASS:=CLASSES!NLOC;
    NEXTHIGHEST:=0;
    $(
    CLPTR+:=2;
    ATOK:=CLASSES!CLPTR;
    TEST ATOK=NEXTRAT THEN
     $(
     CLASSES!CLPTR:=0;
     NATCLASS+:=1
     $)
    OR
     IF ATOK>NEXTHIGHEST THEN NEXTHIGHEST:=ATOK
    $) REPEATUNTIL ATOK=-1;
    CLASSES!NLOC:=NATCLASS;
    CLASSES![NLOC+1]:=NEXTHIGHEST
    $)
   OR
    IF CLASSES![CLPTR+1]>0 THEN ONCLASSES-:=1
   $)
  $);

 LET TTEST(M) = VALOF
  $( LET NTOFILL,ATMAX,VAT,V2=0,NEXTRAT-1,VALENCES!NEXTRAT-M,NIL;
  FOR AT=GFA!NEXTRAT TO ATMAX DO
   $(
   V2:=VALENCES!AT;
   IF V2>VAT DO NTOFILL+:=V2-VAT
   $);
  RESULTIS NTOFILL LE M
  $);

 LET JOINN(AT,NUM) BE
  $( LET CTS1,CTS2=CTSTOP!AT,CTSTOP!NEXTRAT;
  VALENCES!AT-:=NUM;
  VALENCES!NEXTRAT-:=NUM;
  IF NUM>1 DO
   $(
   DOTS!AT+:=NUM-1;
   DOTS!NEXTRAT+:=NUM-1
   $);
  FOR I=1 TO NUM DO
   $(
   CTS1+:=1;
   CTS2+:=1;
   CTABLE!CTS1:=NEXTRAT;
   CTABLE!CTS2:=AT
   $);
  CTSTOP!AT:=CTS1;
  CTSTOP!NEXTRAT:=CTS2
  $);

 LET UNJOINN(AT,NUM) BE
  $(
  VALENCES!AT+:=NUM;
  VALENCES!NEXTRAT+:=NUM;
  IF NUM>1 DO
   $(
   DOTS!AT-:=NUM-1;
   DOTS!NEXTRAT-:=NUM-1
   $);
  CTSTOP!AT-:=NUM;
  CTSTOP!NEXTRAT-:=NUM
  $);

 LET LASTRAT() BE
  $( LET ATMAX,VAT,SOMEAR=NAT-1,NIL,FALSE;
  STACKPTR+:=1;
  STACK!STACKPTR:=0;
  FOR AT=1 TO ATMAX DO
   $(
   VAT:=VALENCES!AT;
   IF VAT>0 DO
    $(
    STACKPTR+:=1;
    STACK!STACKPTR:=AT;
    STACKPTR+:=1;
    STACK!STACKPTR:=VAT;
    JOINN(AT,VAT)
    $)
   $);
  IF NUMARPAT>0 DO SOMEAR:=MARKARATS(ARPATRECS,1,NEXTRAT);
  IF GMTEST(GMTACTICS) DO
   IF CYCTST() DO
    TEST NEXTRAT=GFA!NEXTRAT THEN IF CANONFILTER() DO STRUCFUN()
    OR
      IF HORDATP(NEXTRAT) DO
       $(
       IF CANONFILTER() THEN STRUCFUN();
       UNHORD()
       $);
  IF SOMEAR DO $( NARSTRUCS+:=1; FOR I=1 TO NEXTRAT DO ARTYPE!I:=1 $)
  VAT:=STACK!STACKPTR;
  WHILE VAT>0 DO
   $(
   UNJOINN(STACK![STACKPTR-1],VAT);
   STACKPTR-:=2;
    VAT:=STACK!STACKPTR
   $);
  STACKPTR-:=1
  $);

 LET PACKCOMPS(OLDPTR,NCUSED) = VALOF
  $( LET NEWNCOMP,OLDNCOMP,NSCANPTR,ENDPTR,NCOMP1V,
         CVSAV,NEWPTR=NIL,COMPARY!OLDPTR,NIL,NIL,VALENCES!NEXTRAT,
         NIL,NIL;
  NEWPTR:=OLDPTR+3*OLDNCOMP+NEXTRAT;
  NEWNCOMP:=OLDNCOMP-NCUSED+1;
  COMPARY!NEWPTR:=NEWNCOMP;
  COMPARY![NEWPTR+2]:=0;
  COMPARY![NEWPTR+3]:=NEXTRAT;
  NSCANPTR:=NEWPTR+4;
  ENDPTR:=NEWPTR+3*NEWNCOMP+NEXTRAT;
  COMPARY!ENDPTR:=-1;
  ENDPTR-:=1;
  NCOMP1V:=VALENCES!NEXTRAT;
  FOR CN=1 TO OLDNCOMP DO
   TEST COMPARY![OLDPTR+2]=0 DO
    $(
    CVSAV:=COMPARY![OLDPTR+1];
    OLDPTR+:=3;
    WHILE COMPARY!OLDPTR>0 DO
     $(
     COMPARY!ENDPTR:=COMPARY!OLDPTR;
     ENDPTR-:=1;
     OLDPTR+:=1;
     $);
    COMPARY!ENDPTR:=0;
    COMPARY![ENDPTR-1]:=CVSAV;
    COMPARY![ENDPTR-2]:=-1;
    ENDPTR-:=3
    $)
   OR
    $(
    NCOMP1V+:=COMPARY![OLDPTR+1]-2*COMPARY![OLDPTR+2];
    OLDPTR+:=3;
    WHILE COMPARY!OLDPTR>0 DO
     $(
     COMPARY!NSCANPTR:=COMPARY!OLDPTR;
     NSCANPTR+:=1;
     OLDPTR+:=1
     $)
    $);
  COMPARY![NEWPTR+1]:=NCOMP1V;
  RESULTIS NEWPTR
  $);

 LET RHSBONDS() BE
  $( LET VNR,TMIN,TMAX,Z0,NL=NIL,NIL,NIL,NIL,NIL;

  LET MPARTS(M,CPTR3,SB) BE
   $( LET VMIN,VMAX,AT,BN=NIL,NIL,NIL,NIL;
   TEST M=0 THEN
    $(
    WHILE COMPARY!CPTR3>0 DO CPTR3+:=1;
    CPTR3+:=1;
    TEST CPTR3<COMPPTR THEN
     MPARTS(COMPARY![CPTR3+1],CPTR3+2,COMPARY!CPTR3)
    OR
     IF GMTEST(GMTACTICS) DO
      TEST NCLASS=0 THEN
       TEST NEXTRAT=GFA!NEXTRAT THEN RHSBONDS()
       OR
        IF HORDATP(NEXTRAT) DO
         $(
         RHSBONDS()
         UNHORD()
         $)
      OR
       IF TESTCLASSES(NCLASS) THEN
        $( LET ONC = NCLASS;
        NCLASS:=UPDATECLASSES(ONC);
        TEST NEXTRAT=GFA!NEXTRAT THEN RHSBONDS()
        OR
         IF HORDATP(NEXTRAT) DO
          $(
          RHSBONDS()
          UNHORD()
          $);
        DOWNDATECLASSES(ONC);
        NCLASS:=ONC
        $)
    $)
   OR
    $(
    AT:=COMPARY!CPTR3;
    BN:=VALENCES!AT;
    VMIN:=M-SB+BN;
    IF VMIN<0 DO VMIN:=0;
    TEST M>BN DO VMAX:=BN OR VMAX:=M;
    FOR V=VMIN TO VMAX DO
     $(
     JOINN(AT,V);
     MPARTS(M-V,CPTR3+1,SB-BN);
     UNJOINN(AT,V)
     $)
    $)
   $);

  LET LZMRPARTS(M,N,CPTR2,Z,SB,F,NNONZ) BE
   $( LET VMIN,VMAX,BN,NCPTR2=NIL,NIL,NIL,NIL;
   TEST M=0 THEN
    $( LET OCPTR=COMPPTR;
    COMPPTR:=PACKCOMPS(COMPPTR,NNONZ);
    MPARTS(COMPARY![OCPTR+2],OCPTR+3,COMPARY![OCPTR+1]);
    COMPPTR:=OCPTR
    $)
   OR
    $(
    BN:=COMPARY!CPTR2;
    SB-:=BN;
    N-:=1;
    VMIN:=M-SB;
    IF VMIN<0 DO VMIN:=0;
    IF [Z=0] BITAND [VMIN=0] DO VMIN:=1;
    VMAX:=M-N+Z;
    IF VMAX>BN DO VMAX:=BN;
    IF VMAX>M DO VMAX:=M;
    IF F DO
     $(
     IF [[M GE SB] BITOR [SB LE N]] BITAND [VMIN=0] DO VMIN:=1;
     IF [[M LE BN] BITOR [SB LE N]] BITAND [VMAX=BN] DO VMAX-:=1;
     $);
    NCPTR2:=CPTR2+2;
    WHILE COMPARY!NCPTR2>0 DO NCPTR2+:=1;
    NCPTR2+:=1;
    FOR V=VMIN TO VMAX DO
     $(
     COMPARY![CPTR2+1]:=V;
     TEST V=0 THEN LZMRPARTS(M,N,NCPTR2,Z-1,SB,F,NNONZ)
     OR TEST V=BN THEN LZMRPARTS(M-V,N,NCPTR2,Z,SB,F,NNONZ+1)
     OR LZMRPARTS(M-V,N,NCPTR2,Z,SB,FALSE,NNONZ+1);
     COMPARY![CPTR2+1]:=0;
     $)
    $)
   $);
  IF NEXTRAT=ESTRAT DO
   TEST ESTIMATING THEN $( NCHECKPOINT+:=1; RETURN $)
   OR $( ICHECKPOINT+:=1; ESTRPT(TRUE) $);
  NEXTRAT+:=1;
  IF AVOIDISTHMUS DO
   IF NEXTRAT>1 DO
    $( STATIC $( SOMEISTHMUS = NIL; IAT = NIL; TEM = NIL $)
    IAT:=NEXTRAT;
    WHILE IAT>1 DO
     $(
     IAT-:=1;
     TEM:=VALENCES!IAT;
     VLNCSAV!IAT:=TEM;
     JOINN(IAT,TEM)
     $);
    SOMEISTHMUS:=NOT[NOISTHMUS(NEXTRAT)];
    WHILE IAT<NEXTRAT DO $( UNJOINN(IAT,VLNCSAV!IAT); IAT+:=1 $);
    IF SOMEISTHMUS DO $( NEXTRAT-:=1; RETURN $);
    $);
  TEST NEXTRAT=NAT THEN LASTRAT()
  OR
   $(
   VNR:=VALENCES!NEXTRAT;
   NL:=COMPARY!COMPPTR;
   TMIN:=VNR+[VL-VR]/2;
   IF TMIN<0 DO TMIN:=0;
   TMAX:=[VL+VR]/2;
   Z0:=TMAX-NAT+NEXTRAT;
   TMAX:=TMAX-VRMAX!NEXTRAT;
   IF TMAX>VNR DO TMAX:=VNR;
   IF TMAX>VL DO TMAX:=VL;
   IF [[VNR=VL] BITOR [NL=VL]] BITAND [TMAX=VNR] DO TMAX-:=1;
   FOR T=TMIN TO TMAX DO
    IF (GFA!NEXTRAT=NEXTRAT -> TRUE,TTEST(T)) DO
     $(
     VL+:=VNR-2*T;
     VR-:=VNR;
     LZMRPARTS(T,NL,COMPPTR+1,Z0-T,VL-VNR+2*T,T=VNR,0);
     VL-:=VNR-2*T;
     VR+:=VNR
     $)
   $);
  NEXTRAT-:=1
  $);

 LET SGEN0() BE
  $( LET HIV=0;
  FOR IAT=1 TO NAT DO IF HIV<VALENCES!IAT DO HIV:=VALENCES!IAT;
  IF HIV>[VR/2] DO RETURN;
  IF AVOIDISTHMUS DO
   FOR IAT=1 TO NAT DO IF VALENCES!IAT=1 DO RETURN;
  UNLESS SCOREATS(VRMAX) DO RETURN;
  SCORDER:=RANKORDER(VRMAX,1,NAT,FALSE);
  FOR IAT=1 TO NAT DO
   $(
   SCORDINV![SCORDER!IAT]:=IAT;
   GFA!IAT:=SCORDER![GFA!IAT]
   $);
  INVPERMUTE(GFA,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(TYPNO,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(NUMHS,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(NUMISBS,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(ATTYPE,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(ATTYPEH,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(VALENCES,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(CTSTART,SCORDER,VRMAX,1,NAT);
  INVPERMUTE(CTSTOP,SCORDER,VRMAX,1,NAT);
  FINDTPS();
  GMTACTICS:=MAKEGMTAC();
  HIV:=0;
  FOR IAT=NAT TO 1 BY -1 DO
   $(
   IF HIV<VALENCES!IAT DO HIV:=VALENCES!IAT;
   VRMAX![IAT-1]:=HIV
   $);
  VL:=VALENCES!1;
  VR-:=VL;
  COMPARY!2:=VL;
  RHSBONDS();
  VR+:=VL;
  FOR IAT=NAT TO 1 BY -1 DO FREEVEC(GMTACTICS!IAT);
  FREEVEC(GMTACTICS);
  FREEVEC(SCORDER);
  INVPERMUTE(CTSTOP,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(CTSTART,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(VALENCES,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(ATTYPEH,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(ATTYPE,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(NUMISBS,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(NUMHS,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(TYPNO,SCORDINV,VRMAX,1,NAT);
  INVPERMUTE(GFA,SCORDINV,VRMAX,1,NAT);
  FOR IAT=1 TO NAT DO GFA!IAT:=SCORDINV![GFA!IAT]
  $);

 LET MPARTSISB(IAT,M,SB) BE
  $(

  LET IPARTSISB(M,N,B,IAT,NXM,NXSB) BE
   TEST N=0 THEN MPARTSISB(IAT,NXM,NXSB)
   OR
    $(
    IF B>M DO B:=M;
    FOR V=(M+N-1)/N TO B DO
     $( LET VT2 = 2*V;
     VALENCES!IAT-:=VT2;
     VR-:=VT2;
     NUMISBS!IAT+:=V;
     TEST [ATTYPE!IAT=ATTYPE![IAT-1]] BITAND
          [NUMHS!IAT=NUMHS![IAT-1]] BITAND
          [NUMISBS!IAT=NUMISBS![IAT-1]] THEN
      $(
      GFA!IAT:=GFA![IAT-1];
      TYPNO!IAT:=TYPNO![IAT-1]
      $)
     OR
      $(
      GFA!IAT:=IAT;
      TYPNO!IAT:=TYPNO![IAT-1]+1
      $);
     IPARTSISB(M-V,N-1,V,IAT+1,NXM,NXSB);
     NUMISBS!IAT-:=V;
     VR+:=VT2;
     VALENCES!IAT+:=VT2
     $)
    $);
  TEST IAT>NAT THEN SGEN0()
  OR
   $( LET ATYP,ATNH,IPB,IPN,BN,VMIN,VMAX=
          ATTYPE!IAT,NUMHS!IAT,ISBMAXS!IAT,0,NIL,NIL,NIL;
   IPN:=IAT+1;
   UNTIL [ATYP NE ATTYPE!IPN] BITOR [ATNH NE NUMHS!IPN] BITOR [IPN>NAT] DO
    IPN+:=1;
   IPN-:=IAT;
   BN:=IPN*IPB;
   VMIN:=M-SB+BN;
   IF VMIN<0 DO VMIN:=0;
   TEST BN>M THEN VMAX:=M OR VMAX:=BN;
   FOR V=VMIN TO VMAX DO
    IPARTSISB(V,IPN,IPB,IAT,M-V,SB-BN)
   $)
  $);

LET ISBALLOC() BE
 $( STATIC $( VM1O2 = NIL; ISBMAX = NIL; SUMMAX = NIL; TOTISB = NIL $);
 SUMMAX:=0;
 FOR IAT=1 TO NAT DO
  $(
  VM1O2:=[VALENCES!IAT-1]/2;
  ISBMAX:=ADDLISBS![ATTYPE!IAT];
  IF ISBMAX>VM1O2 DO ISBMAX:=VM1O2;
  SUMMAX+:=ISBMAX;
  ISBMAXS!IAT:=ISBMAX
  $);
 TOTISB:=[VR/2]-NAT+1;
 IF TOTISB>SUMMAX DO TOTISB:=SUMMAX;
 UNTIL TOTISB<0 DO $( MPARTSISB(1,TOTISB,SUMMAX); TOTISB-:=1 $)
 $);

 LET MPARTSH(GROUPNO,M,SB,IAT) BE
  $(

  LET IPARTS(M,N,B,IAT,NXGROUPNO,NXM,NXSB) BE
   TEST N=0 THEN MPARTSH(NXGROUPNO,NXM,NXSB,IAT)
   OR
    $(
    IF B>M DO B:=M;
    FOR V=(M+N-1)/N TO B DO
     $(
     VALENCES!IAT-:=V;
     NUMHS!IAT:=V;
     IPARTS(M-V,N-1,V,IAT+1,NXGROUPNO,NXM,NXSB);
     VALENCES!IAT+:=V
     $)
    $);
  TEST IAT>NAT THEN ISBALLOC()
  OR
   $( LET IPB,IPN,BN,VMIN,VMAX=VALENCES!IAT-1,NUMS!GROUPNO,NIL,NIL,NIL;
   BN:=IPN*IPB;
   VMIN:=M-SB+BN;
   IF VMIN<0 DO VMIN:=0;
   TEST BN>M THEN VMAX:=M OR VMAX:=BN;
   FOR V=VMIN TO VMAX DO
    IPARTS(V,IPN,IPB,IAT,GROUPNO+1,M-V,SB-BN)
   $)
  $);
 NAT:=NUMAT;
 VS:=TVS;
 NUMS:=TNUMS;
 ISBS:=TISBS;
 ADDLISBS:=TADDLISBS;
 AVOIDISTHMUS:=AVOIDISTH;
 VALENCES:=NEWVEC(NAT);
 GFA:=NEWVEC(NAT);
 TYPNO:=NEWVEC(NAT);
 VRMAX:=NEWVEC(NAT);
 COMPARY:=NEWVEC(2*NAT*NAT-NAT);
 CLASSPTRS:=NEWVEC(NAT);
 CLASSES:=NEWVEC(NAT*NAT+3*NAT);
 REMOVED:=NEWVEC(NAT);
 OLDNOS:=NEWVEC(NAT);
 NEWNOS:=NEWVEC(NAT);
 ADJM:=NEWVEC(NAT*NAT);
 CSCRATCH:=NEWVEC(NAT);
 SCORDINV:=NEWVEC(NAT);
 LTPS:=NEWVEC(NUMPAT);
 HTPS:=NEWVEC(NUMPAT);
 NUMISBS:=NEWVEC(NAT);
 ISBMAXS:=NEWVEC(NAT);
 IF AVOIDISTHMUS DO
  $(
  VLNCSAV:=NEWVEC(NAT);
  ETR:=NEWVEC(NAT)
  $);
 VSUM:=1;
 TYPN:=10;
 ATMAX:=0;
 FOR IIN=1 TO NIN DO
  $(
  TYPN+:=1;
  ATMIN:=ATMAX+1;
  ATMAX+:=NUMS!IIN;
  FOR AT=ATMIN TO ATMAX DO
   $(
   ATTYPE!AT:=IIN;
   ATTYPEH!AT:=ATHSTART!IIN;
   NISB:=ISBS!IIN;
   NUMISBS!AT:=NISB;
   VALENCES!AT:=VS!IIN-2*NISB;
   DOTS!AT:=0;
   CTSTART!AT:=VSUM;
   CTSTOP!AT:=VSUM-1;
   REMOVED!AT:=0;
   OLDNOS!AT:=AT;
   VSUM+:=VALENCES!AT
   $)
  $);
 FOR ADJMIX=NAT*NAT TO 1 BY -1 DO ADJM!ADJMIX:=0;
 COMPARY!1:=1;
 IF NAT>1 DO
  $(
  COMPARY!3:=0;
  COMPARY!4:=1;
  COMPARY!5:=-1;
  $);
 VSUM-:=1;
 ATTYPE!0:=0;
 NUMHS!0:=0;
 TYPNO!0:=9;
 VL:=0;
 VR:=VSUM-NUMS!0;
 IF [VR REM 2]=1 DO RETURN;
 TEST NAT=1 THEN
  IF [VR/2] LE ADDLISBS![ATTYPE!1] DO
   $(
   NUMISBS!1+:=VR/2;
   STRUCFUN()
   $)
 OR
  $(
  ESTRAT:=0;
  ESTOPT:=MSRUNTIME();
  ESTARTT0:=ESTOPT;
  ESTIMATING:=TRUE;
  ESTLOOP:
  ESTRAT+:=1;
  NCHECKPOINT:=0;
  ESTARTT:=ESTOPT;
  MPARTSH(1,NUMS!0,VSUM-NAT,1);
  ESTOPT:=MSRUNTIME();
  IF [ESTOPT-ESTARTT]<500 DO
   IF [ESTOPT-ESTARTT0]<1500 DO
    IF ESTRAT<[NAT-1] DO
     IF NCHECKPOINT<100 DO GOTO ESTLOOP;
  ESTIMATING:=FALSE;
  ICHECKPOINT:=0;
  MPARTSH(1,NUMS!0,VSUM-NAT,1)
  $);
 IF AVOIDISTHMUS DO
  $(
  FREEVEC(ETR);
  FREEVEC(VLNCSAV)
  $);
 FREEVEC(ISBMAXS);
 FREEVEC(NUMISBS);
 FREEVEC(HTPS);
 FREEVEC(LTPS);
 FREEVEC(SCORDINV);
 FREEVEC(CSCRATCH);
 FREEVEC(ADJM);
 FREEVEC(NEWNOS);
 FREEVEC(OLDNOS);
 FREEVEC(REMOVED);
 FREEVEC(CLASSES);
 FREEVEC(CLASSPTRS);
 FREEVEC(COMPARY);
 FREEVEC(VRMAX);
 FREEVEC(TYPNO);
 FREEVEC(GFA);
 FREEVEC(VALENCES)
 $);
